/**
 *  @file SocketStream.cpp
 */
#include "SocketStream.h"
#include "../common/CppMemPool.h"
#include "../common/UtilFuncT.h"
#include "SocketTimeoutException.h"
#include "SocketException.h"

namespace cppflib
{

namespace net
{

SocketStream::SocketStream(void)
{
}

SocketStream::SocketStream(Socket *pSock, int recvTimeout)
{
   this->pSock = pSock;
   cppmempool::Retain(this->pSock);

   this->recvTimeout = recvTimeout;
}

SocketStream::~SocketStream(void)
{
   Close();
}

void SocketStream::Close()
{
   if (pSock) {
      cppmempool::Release(pSock);
      pSock = NULL;
   }
}

void SocketStream::Flush()
{
   // not valid
}

int SocketStream::Read(collections::ArrayByte &buffer)
{
   return Read(buffer, 0, static_cast<int>(buffer.GetSize()));
}

int SocketStream::Read(collections::ArrayByte &buffer, int offset, int count)
{
   if (count < 0 || offset < 0 || offset >= static_cast<int>(buffer.GetSize()))
      return 0;

   // use the smaller one
   count = cppflib::Min<int>(count, static_cast<int>(buffer.GetSize() - offset));

   int ret = pSock->ReceiveTimeout(recvTimeout, buffer.GetRawPtr() + offset, count, 0);
   if (ret < 0)
      throw SocketTimeoutException(_S("Receive timeout"));
   else if (ret == 0)
      throw SocketException(_S("Socket error or is already closed"));
   
   return ret;
}

/**
 *  Read a single byte
 *
 *  @return byte read
 */
int SocketStream::Read()
{
   u8_t b = 0;
   
   int ret = pSock->ReceiveTimeout(recvTimeout, &b, 1, 0);
   if (ret < 0)
      throw SocketTimeoutException(_S("Receive timeout"));
   else if (ret == 0)
      throw SocketException(_S("Socket error or is already closed"));

   return static_cast<int>(b) & 0xff;
}

i64_t SocketStream::Seek(i64_t offset, seekorigin_t origin)
{
   // not valid
   return 0;
}

int SocketStream::Write(collections::ArrayByte &buffer)
{
   return Write(buffer, 0, static_cast<int>(buffer.GetSize()));
}

int SocketStream::Write(collections::ArrayByte &buffer, int offset, int count)
{
   if (count < 0 || offset < 0 || offset >= static_cast<int>(buffer.GetSize()))
      return 0;

   // use the smaller one
   count = cppflib::Min<int>(count, static_cast<int>(buffer.GetSize() - offset));

   return pSock->Send(buffer.GetRawPtr() + offset, count, 0);
}

bool SocketStream::Write(u8_t val)
{
   return (pSock->Send(&val, 1, 0) > 0);
}



} // end of namespace net

} // end of namespace cppflib
